package com.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.*;

/**
 * @ClassName JDBCUtil
 * @Description ToDo
 * @Auther teacher Bai
 * @Date 2020/12/26 14:23
 */
public class JDBCUtil {

    //提出所有的公共参数
    public static String DRIVER;
    public static String URL;
    public static String USER;
    public static String PASSWORD;
    /**
     * 驱动只需要加载一次就可以了，所以放在静态代码块中
     */
    static {
        try {
            //1.读取 db.properties配置文件中共的信息
            InputStream stream = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");
            //2.创建一个properties文件对象，将流读取进去
            Properties p = new Properties();
            //3.使用创建的properties文件对象，加载读取到的流
            p.load(stream);

            //4.通过加载过流的properties文件对象 去读取配置文件中的配置信息 ，根据key取 value
            DRIVER = (String)p.get("driver");
            URL = (String)p.get("url");
            USER = (String)p.get("user");
            PASSWORD = (String)p.get("password");

            Class.forName(DRIVER);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建连接的方法封装
     * @return
     */
    public static Connection getConn(){
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(URL, USER, PASSWORD);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return conn;
    }

    /**
     * 封装返回List<List>数据类型的方法</>
     * 方法的三要素：
     *      返回值，方法名，参数列表
     * Object... obj 代表可变参数的个数。
     * @return
     */
    public static List<List> queryList(String sql, Object... obj){
        Connection conn = getConn();
        PreparedStatement ps = null;
        List<List> bigList = null;
        ResultSet set = null;
        try {
            //3.sql预编译
            ps = conn.prepareStatement(sql);
            //当传入的数组不为null 时，再判断数组的长度是否大于0，如果大于0，证明要向sql语句中设置参数
            //设置参数
            setParmeter(ps,obj);
            //4.执行sql
            set = ps.executeQuery();
            bigList = new ArrayList<>();
            while (set.next()){
                List<Object> list = new ArrayList<>();
                for (int i = 0; i < set.getMetaData().getColumnCount(); i++) {
                    list.add(set.getObject(i+1));
                }
                bigList.add(list);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            close(set,ps,conn);
        }
        return bigList;
    }

    /**
     * 封装通用向sql语句设置参数的方法
     * @param ps
     * @param obj
     */
    public static void setParmeter(PreparedStatement ps, Object... obj){
        //当传入的数组不为null 时，再判断数组的长度是否大于0，如果大于0，证明要向sql语句中设置参数
        try {
            if(obj.length>0){
                for (int i = 0; i < obj.length; i++) {
                    ps.setObject(i+1,obj[i]);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    /**
     * 封装返回List<Map<String, Object>>数据类型的方法</>
     * 方法的三要素：
     *      返回值，方法名，参数列表
     *
     * @return
     */
    public static List<Map<String, Object>> queryListMap(String sql, Object... obj){
        Connection conn = getConn();
        PreparedStatement ps = null;
        List<Map<String, Object>> bigList = null;
        ResultSet set = null;
        try {
            //3.sql预编译
            ps = conn.prepareStatement(sql);
            //设置参数
            setParmeter(ps,obj);
            //4.执行sql
            set = ps.executeQuery();
            bigList = new ArrayList<>();
            while (set.next()){
                Map<String, Object> map = new HashMap<>();
                for (int i = 0; i < set.getMetaData().getColumnCount(); i++) {
                    map.put(set.getMetaData().getColumnName(i+1),set.getObject(i+1));
                }
                bigList.add(map);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            close(set,ps,conn);
        }
        return bigList;
    }

    /**
     * 设置通用的增删改方法/更新方法
     * @param sql
     * @param obj
     * @return
     */
    public static int update(String sql, Object... obj){
        Connection conn = getConn();
        PreparedStatement ps = null;
        try {
            //3.sql预编译
            ps = conn.prepareStatement(sql);
            //设置参数
            setParmeter(ps,obj);
            //4.执行sql
            int i = ps.executeUpdate();
            return i;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            close(null,ps,conn);
        }
        return -1;//返回-1代表插入失败
    }

    /**
     * 封装通用的关闭资源方法
     * @param set
     * @param ps
     * @param conn
     */
    public static void close(ResultSet set, PreparedStatement ps,Connection conn){
        try {
            if(set!=null){
                set.close();
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        try {
            if(ps!=null){
                ps.close();
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        try {
            if(conn!=null){
                conn.close();
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    /**
     * 封装返回主键的方法
     * @param sql
     * @param obj
     * @return
     */
    public static int getPrimaryKey(String sql, Object... obj){
        Connection conn = getConn();
        PreparedStatement ps = null;
        ResultSet set = null;
        try {
            //3.sql预编译
            ps = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
            //设置参数
            setParmeter(ps,obj);
            //4.执行sql
            ps.executeUpdate();
            //获取主键  获取sql语句执行后得到的所有主键
            set = ps.getGeneratedKeys();
            Object o = null;
            if(set.next()){
                o = set.getObject(1);
            }
            return Integer.parseInt(o+"");
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            close(set,ps,conn);
        }
        return -1;//返回-1代表获取失败
    }


}
